package com.tomato.dynamic.threadpool.core;

import com.tomato.dynamic.threadpool.common.config.DynamicThreadPoolProperties;
import com.tomato.dynamic.threadpool.common.config.ThreadPoolProperties;
import com.tomato.dynamic.threadpool.common.enums.QueueTypeEnum;
import com.tomato.dynamic.threadpool.core.reject.RejectHandlerGetter;
import com.tomato.dynamic.threadpool.core.support.PropertiesBinder;
import com.tomato.dynamic.threadpool.core.support.ThreadFactoryBuilder;
import com.tomato.dynamic.threadpool.core.thread.DynamicThreadPoolExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

import static com.tomato.dynamic.threadpool.common.constant.DynamicThreadPoolConstant.*;

/**
 * 线程池bean注册器
 *
 * @author lizhifu
 * @date 2022/4/11
 */
@Slf4j
public class DynamicThreadBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        DynamicThreadPoolProperties properties = new DynamicThreadPoolProperties();
        PropertiesBinder.bindDtpProperties(environment, properties);
        log.info("DynamicThreadBeanDefinitionRegistrar 注册Bean定义 properties: {}", properties);
        properties.getExecutors().forEach(dynamicThreadPool -> {
            String beanName = dynamicThreadPool.getThreadPoolName();
            log.info("DynamicThreadBeanDefinitionRegistrar 注册Bean定义 beanName: {}", beanName);
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DynamicThreadPoolExecutor.class);
            Object[] args = buildArgs(dynamicThreadPool);
            for (Object arg : args) {
                builder.addConstructorArgValue(arg);
            }
            buildProperties(dynamicThreadPool).forEach(builder::addPropertyValue);
            registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
        });
    }

    /**
     * class 属性构造器
     * @param tpp
     * @return
     */
    private Map<String, Object> buildProperties(ThreadPoolProperties tpp) {
        Map<String, Object> properties = new HashMap();
        properties.put(THREAD_POOL_NAME, tpp.getThreadPoolName());
        properties.put(ALLOW_CORE_THREAD_TIMEOUT, tpp.isAllowCoreThreadTimeOut());
        properties.put(WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN, tpp.isWaitForTasksToCompleteOnShutdown());
        properties.put(AWAIT_TERMINATION_SECONDS, tpp.getAwaitTerminationSeconds());
        properties.put(PRE_START_ALL_CORE_THREADS, tpp.isPreStartAllCoreThreads());
        properties.put(RUN_TIMEOUT_THRESHOLD, tpp.getRunTimeoutThreshold());
        properties.put(QUEUE_TIMEOUT_THRESHOLD, tpp.getQueueTimeoutThreshold());

        return properties;
    }

    /**
     * class 构造器参数
     * @param tpp
     * @return
     */
    private Object[] buildArgs(ThreadPoolProperties tpp) {
        BlockingQueue<Runnable> taskQueue = QueueTypeEnum.buildBlockingQueue(tpp.getQueueType(), tpp.getQueueCapacity());
        return new Object[] {
                tpp.getCorePoolSize(),
                tpp.getMaximumPoolSize(),
                tpp.getKeepAliveTime(),
                tpp.getUnit(),
                taskQueue,
                ThreadFactoryBuilder.newBuilder().prefix(tpp.getThreadNamePrefix()).build(),
                RejectHandlerGetter.buildRejectedHandler(tpp.getRejectedHandlerType())
        };
    }
}
